package com.example.shop.redis.service;

import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.*;
import java.util.concurrent.TimeUnit;

public interface LettuceClient{
//===============================通用=============================================


    /**
    * lua脚本的执行
    * @param script lua脚本
    * @param keys KEYS的键名
    * @param args ARGV的值
    * @param <T> 返回值类型
    * @return 返回脚本的执行结果
    */
    <T>  T execLua(RedisScript<T> script, List<String> keys, Object... args);
    /**
    * lua脚本的执行
    * @param script lua脚本
    * @param resultSerializer 返回结果的双向序列化器
    * @param keys KEYS的键名
    * @param args ARGV的值
    * @param <T> 返回值类型
    * @return 返回脚本的执行结果
    */
    <T>  T execLua(RedisScript<T> script, RedisSerializer<T> resultSerializer,
                     List<String> keys, Object... args);

    /**
    * 判断指定的key是否存在
    * @param key 要知道存在的键名，任意类型
    * @return 返回是否存在，存在为true
    */
    boolean existKey(String key);
    /**
    * 统计keys有多少个key是存在的
    * @param keys 要统计的键名，任意类型
    * @return 返回存在key的个数
    */
    long countKey(List<String> keys);
    /**
    * 移除给定 key的生存时间
    * @param key 要移除过期时间的键名，任意类型
    * @return 当生存时间移除成功时，返回1,如果 key 不存在或 key 没有设置生存时间,返回 0。
    */
    boolean persist(String key);
    /**
    * 获取指定给key，剩下的过期时间
    * @param key 要获取剩下的过期时间的键名，任意类型
    * @param unit 返回的过期时间的单位
    * @return 返回剩下的过期时间，如果没有设置过期时间，则返回-1
    */
    long getExpire(String key,TimeUnit unit);

    /**
    * 获取指定给key，剩下的过期时间
    * @param key 要获取剩下的过期时间的键名，任意类型
    * @return 返回剩下的过期时间，单位是秒，如果没有设置过期时间，则返回-1
    */
    long getExpire(String key);

    /**
    * 给指定key，设置过期时间
    * @param key 要设置过期时间的键名，任意类型
    * @param timeout 过期时间，单位是秒
    * @return 返回设置是否成功，成功返回true，如果该key原本就有过期时间，则也是返回true，并且会重新设置过期时间。如果指定的key不存在，则返回false
    */
    boolean expire(String key,long timeout);
    /**
    * 给指定key，设置过期时间
    * @param key 要设置过期时间的键名，任意类型
    * @param timeout 过期时间
    * @param  unit 过期时间的单位
    * @return 返回设置是否成功，成功返回true，如果该key原本就有过期时间，则也是返回true，并且会重新设置过期时间。如果指定的key不存在，则返回false
    */
    boolean expire(String key,long timeout,TimeUnit unit);
    /**
    * 删除集合里的所有key
    * @param key 要删除的键名，，任意类型
    * @return 返回成功删除key的个数
    */
    long batchDelKey(List<String> key);
    /**
    * 删除指定的key
    * @param key 要删除的键名，任意类型
    * @return 返回是否删除成功。成功为true
    */
    boolean delKey(String key);
    //================================key-value============================================

    /**
    * 指定key，增长指定delta值。如果指定的key非数值，则会报错：io.lettuce.core.RedisCommandExecutionException
    * @param key 键值对的键名
    * @param delta 增长量
    * @return 返回增长后的值,如果key不存在，则会重新新建一个key
    */
    long incr(String key,long delta);
    /**
    * 指定key，减少指定delta值。如果指定的key非数值，则会报错：io.lettuce.core.RedisCommandExecutionException
    * @param key 键值对的键名
    * @param delta 减少量
    * @return 返回减少后的值
    */
    long decr(String key,long delta);
    /**
    * 获取指定key的value
    * @param key 键值对的键名
    * @return 返回value
    */
    Object get(String key);

    /**
    * 使用lua脚本，嵌套获取一个键值对。
    * 比如：
    * keyValue=RedisKey.USER_ID+account = user:id:账户
    * preKey=RedisKey.USER_INFO.getKey() = user:info:
    * 在redis缓存里
     *          user:id:账户  ->  123
     *          user:info:123  ->  用户信息
    * 先获取keyValue的value值(123)，该value值再加上前缀preKey作为key(user:info:123)，再次进行get其值(用户信息)
    * @param keyValue 该key的value会被作为key再进行一次查询
    * @param preKey  keyValue的value作为key的前缀
    * @param targetClass 返回的class类型
    * @return 返回2次get的结果,如果第一次get为nil，则不会进行下一次get，直接返回null
    */
    <T> T getValueAsKey(String keyValue,String preKey,Class<T> targetClass);

    /**
    * 添加一个k-v，不管key存不存在，如果存在，则直接覆盖原本的k-v
    * @param key 键值对的键名
    * @param value 值
    */
    void set(String key,Object value);
    /**
    * 设置一个k-v。如果key不存在，则添加k-v，否则不添加
    * @param key 键值对的键名
    * @param value 值
    * @return 如果添加了返回true，否则返回false
    */
    boolean setNx(String key,Object value);
    /**
    * 设置一个k-v。如果key不存在，则添加k-v,并为该k-v添加过期时间，单位是秒
    * @param key 键值对的键名
    * @param value 值
    * @param timeout 过期时间，单位是秒
    */
    void setEx(String key,Object value,long timeout);
    /**
    * 设置一个k-v。如果key不存在，则添加k-v,并为该k-v添加过期时间
    * @param key 键值对的键名
    * @param value 值
    * @param timeout 过期时间
    * @param unit 过期时间的单位
    */
    void setEx(String key,Object value,long timeout, TimeUnit unit);
    //===============================hashmap=============================================
    /**
    * 判断指定key集合map里的field字段是否存在
    * @param key map集合的键名
    * @param field 字段
    * @return 返回存在性，如果存在，返回true。如果map集合不存在，则也是返回false
    */
    boolean hExistField(String key, String field);
    /**
    * 获取指定key集合map里的指定字段对应的value
    * @param key map集合的键名
    * @param field 字段
    * @return 返回指定key集合map里的指定字段对应的value
    */
    Object hGet(String key,String field);
    /**
    * 获取指定key集合map
    * @param key map集合的键名
    * @return 返回指定key集合map，如果不存在key对应的map，则返回空map
    */
    Map<Object, Object> hGetMap(String key);
    /**
    * 如果指定key集合map不存在，则创建一个key集合map，并将map集合存入其中
    * @param key map集合的键名
    * @param map map集合
    */
    <T> void hSetMap(String key,Map<String,T> map);
    /**
    * 如果指定key集合map不存在，则会创建一个集合map。并将field存入其中
    * 如果key集合里的field存在，则不会将field-value存入其中
    * @param key map集合的键名
    * @param field 字段(map集合中的key)
    * @param value 值(map集合里的value)
    * @return 如果field-value成功存入map中，则返回true
    */
    boolean hPutNx(String key,String field,Object value);
    /**
    * 如果指定key集合map不存在，则创建一个key集合map，并将field-value存入其中
    * @param key map集合的键名
    * @param field 字段(map集合中的key)
    * @param value 值(map集合里的value)
    */
    void hPut(String key,String field,Object value);
    /**
    * 删除指定key集合map里的field字段所对应的k-v
    * @param key map集合的键名
    * @param fields 字段(map集合中的key)
    * @return  返回删除后，map集合里剩下的k-v的个数
    */
    long hDel(String key,String... fields);
    //===============================set集合=============================================

    /**
    * 判断指定key集合set里的value是否存在
    * @param key set集合的键名
    * @param value 要知道存在的值
    * @return 返回存在性，true存在，false不存在，如果指定key不存在，也是返回false
    */
    boolean sExist(String key, Object value);
    /**
    * 随机获取指定key集合set里的指定元素个数。注意：是可以重复获取的
    * @param key set集合的键名
    * @param count 获取元素的个数
    * @return 返回随机获取到的元素，如果key不存在，则返回空
    */
    List<Object> sRandomGet(String key,long count);
    /**
    * 获取指定key集合的set
    * @param key set集合的键名
    * @return 返回set集合，如果key集合set不存在，则返回空
    */
    Set<Object> sGetSet(String key);
    /**
    * 如果指定key集合Set不存在，则创建一个set集合，并将values存入其中
    * @param key set集合的键名
    * @param values 值
    * @return 返回添加values后set集合里的元素个数
    */
    long sAdd(String key,Object... values);

    /**
    * 移除指定key集合Set里的values
    * @param key set集合的键名
    * @param values 要移除的值
    * @return 返回移除后set集合里的元素个数。如果key不存在，返回0
    */
    long sRemove(String key,Object... values);
    //================================列表===============================================

    /**
    * 获取指定key列表的长度
    * @param key 列表的键名
    * @return 返回列表长度，如果key不存在，返回0
    */
    long lGetListSize(String key);

    /**
    * 获取指定key列表的指定范围内的子列表
    * @param key 列表的键名
    * @param start 子列表的起始元素下标，如果为负数，则认为是0
    * @param end  子列表的终止元素下标
    * @return 返回子列表，如果指定的end或者start超过列表下标，则返回不超过的部分,如果全部超出或者key不存在，则返回空
    */
    List<Object> lGet(String key,long start,long end);

    /**
    * 获取指定key列表的指定下标元素
    * @param key 列表的键名
    * @param index 下标
    * @return 返回指定下标元素,如果超出范围，或者key不存在，则返回null
    */
    Object lGetIndex(String key,long index);

    /**
    * 如果key存在，则右追加，如果不存在，则不创建列表，也不追加value
    * @param key 列表的键名
    * @param value 值
    * @return 返回列表中的元素个数。如果key列表不存在，返回0
    */
    long lRPushNx(String key,Object value);
    /**
    * 如果key存在，则左追加，如果不存在，则不创建列表，也不追加value
    * @param key 列表的键名
    * @param value 值
    * @return 返回列表中的元素个数。如果key列表不存在，返回0
    */
    long lLPushNx(String key,Object value);
    /**
    * 如果key不存在，则会创建一个key列表，将values从左到右依次右放入指定key列表中
    * @param key 列表的键名
    * @param values 值
    * @return 返回列表中的元素个数
    */
    long lRPush(String key,Object... values);
    /**
    * 如果key不存在，则会创建一个key列表，将values从左到右依次左放入指定key列表中
    * @param key 列表的键名
    * @param values 值
    * @return 返回列表中的元素个数
    */
    long lLPush(String key,Object... values);
    /**
    * 指定key列表左弹出第一个元素。即第一个元素将出队
    * @param key 列表的键名
    * @return 返回弹出的元素，如果key不存在返回null
    */
    Object lLPop(String key);
    /**
    * 指定key列表右弹出第一个元素。即第一个元素将出队
    * @param key 列表的键名
    * @return 返回弹出的元素，如果key不存在返回null
    */
    Object lRPop(String key);
    /**
    * 除去指定key列表里指定范围内的元素。如果超出范围，则只去除不超出范围的元素
    * @param key 列表的键名
    * @param start 起始元素下标
    * @param end 终止元素下标（包含）
    */
    void lTrim(String key,long start,long end);
    //=============================有序集合===========================================

    /**
    * 查找有序集合中value的排名，即按分数升序排名，排名从0开始，即0对应的则是最小分数
    * @param key 有序集合的键名
    * @param value 要知道其排名的值
    * @return 按分数升序排名，返回value的在有序集合中的排名。如果value不在有序集合中，则返回null
    */
    Long zRank(String key,Object value);
    /**
    * 注意：该方法是升序，即从小到大排序
    *筛选出key有序集合中分数介于[min,max]中的所有元素，并从筛选出来的结果中，对头偏移offset个元素，
    * 返回偏移后的count个元素。
    * 比如：min：1 max：5 offset：2 count：1
    * 则返回分数介于【1,5】的元素,假设有5个(1,2,3,4,5),那么偏移2个，则得到(3,4,5)返回1个元素，即 3。
    * @param key 有序集合的键名
    * @param min 最小分数
    * @param max 最大分数
    * @param offset 偏移量
    * @param count 返回的元素个数
    * @return 筛选后的元素集合
    */
    <T> Set<T> zsRangeByScoreAsc(String key, double min, double max, long offset, long count);
    /**
    * 注意：该方法是降序，即从大到小排序
    *筛选出key有序集合中分数介于[min,max]中的所有元素，并从筛选出来的结果中，对头偏移offset个元素，
    * 返回偏移后的count个元素。
    * @param key 有序集合的键名
    * @param min 最小分数
    * @param max 最大分数
    * @param offset 偏移量
    * @param count 返回的元素个数
    * @return 筛选后的元素集合
    */
    <T> Set<T> zsRangeByScoreDesc(String key, double min, double max, long offset, long count);
    /**
    * 获取指定元素下标范围里的所有元素
    * @param key 有序集合的键名
    * @param start 元素的起始下标
    * @param end 元素的结尾下标（包含）
    * @return 返回范围内的元素集合，如果超出范围，返回空set，而不是null
    */
    <T> Set<T> zsRange(String key, long start, long end);
    /**
    * 如果有序集合key不存在，则创建一个有序集合key，并添加一个分数为score的value到key有序集合中
    * 如果插入的value已经存在，则会更新它的分数score。返回false
    * 如果插入的分数已经有相同的，只能说明同等级
    * @param key 有序集合的键名
    * @param value 值
    * @param score 分数，用于在有序集合中排名
    * @return 添加的value不存在，则返回true，如果存在，则返回false
    */
    boolean zsAdd(String key,Object value,double score);

    /**
    * 如果有序集合key不存在，则创建一个有序集合key，并批量添加元素到有序集合中
     * 注意：values必须不能为空元素
    * @param key 有序集合的键名
    * @param values 要添加的值(值，分数)
    * @return 返回成功添加的个数，即添加的value不存在，则返回true，如果存在，则返回false
    */
    long zsAdd(String key,Set<ZSetOperations.TypedTuple<Object>> values);
    /**
    * 移除指定key有序集合里的所有values
    * @param key 有序集合的键名
    * @param values 值
    * @return 返回成功删除元素的个数
    */
    long zsRemove(String key,Object... values);

    /**
    * 移除指定分数范围内的元素
    * @param key 有序集合的键名
    * @param min 最小分数
    * @param max 最大分数
    * @return 返回移除元素的个数
    */
    long zsRemoveRangeByScore(String key,double min,double max);
    
//=============================HyperLogLog基数===========================================

//=============================geospatial地理位置===========================================


}
